package com.phiture.erp.finance.core.listener;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.phiture.erp.common.enums.ErpAuditStatus;
import com.phiture.erp.finance.common.enums.ErpFinanceStatementStatusEnum;
import com.phiture.erp.finance.core.event.ErpFinancePaymentEvent;
import com.phiture.erp.finance.core.pojo.dto.ErpFinancePaymentEventDTO;
import com.phiture.erp.finance.core.service.ErpFinancePaymentService;
import com.phiture.erp.finance.core.service.ErpFinanceStatementService;
import com.phiture.erp.finance.dal.entity.ErpFinancePaymentItemDO;
import com.phiture.erp.finance.dal.entity.ErpFinanceStatementDO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.phiture.erp.common.constants.ErrorCodeConstants.CHANGE_FINANCE_STATEMENT_TRANSACTION_AMOUNT_ERROR;
import static com.phiture.erp.finance.common.enums.ErpFinanceStatementStatusEnum.ALREADY_SETTLED;

@Slf4j
@Component
@RequiredArgsConstructor
public class ErpFinancePaymentListener {
    private final ErpFinancePaymentService paymentService;
    private final ErpFinanceStatementService statementService;

    @Order(1)
    @EventListener(ErpFinancePaymentEvent.class)
    public void changeFinanceStatement(ErpFinancePaymentEvent event) {
        ErpFinancePaymentEventDTO dto = event.getEventDTO();
        List<ErpFinancePaymentItemDO> paymentItemList = paymentService.getFinancePaymentItemListByPaymentId(dto.getFinancePaymentId());
        if(CollUtil.isEmpty(paymentItemList)){
            log.error("[ErpFinancePaymentListener.changeFinanceStatement] (id:{})未查询到付款单明细", dto.getFinancePaymentId());
            return;
        }
        List<Long> statementIds = paymentItemList.stream().map(ErpFinancePaymentItemDO::getBizId).collect(Collectors.toList());
        List<ErpFinanceStatementDO> financeStatementList = statementService.getFinanceStatementList(statementIds);
        if(CollUtil.isEmpty(financeStatementList)){
            log.error("[ErpFinancePaymentListener.changeFinanceStatement] (statementIds:{})未查询到对账单明细", statementIds);
            return;
        }

        Map<Long, BigDecimal> paymentPriceMap = paymentItemList.stream().collect(Collectors.toMap(ErpFinancePaymentItemDO::getBizId, ErpFinancePaymentItemDO::getPaymentPrice));
        List<ErpFinanceStatementDO> changeList = processErpFinanceStatement(dto.getFinancePaymentStatus(), financeStatementList, paymentPriceMap);
        try {
            statementService.batchChangeTransactionAmount(changeList);
        }catch (Exception e){
            log.error("[ErpFinancePaymentListener.changeFinanceStatement] 变更对账单的交易金额失败，dto:{}, changeList:{}, exMsg:{}", JSONUtil.toJsonStr(dto), JSONUtil.toJsonStr(changeList), e.getMessage());
            throw exception(CHANGE_FINANCE_STATEMENT_TRANSACTION_AMOUNT_ERROR);
        }
    }

    private  List<ErpFinanceStatementDO> processErpFinanceStatement(Integer paymentStatus, List<ErpFinanceStatementDO> financeStatementList, Map<Long, BigDecimal> paymentPriceMap){
        List<ErpFinanceStatementDO> statementList = new ArrayList<>(financeStatementList.size());
        ErpAuditStatus auditStatus = ErpAuditStatus.fromStatus(paymentStatus);
        switch (auditStatus){
            case APPROVE:
                for (ErpFinanceStatementDO statementDO : financeStatementList) {
                    if(ALREADY_SETTLED == ErpFinanceStatementStatusEnum.fromStatus(statementDO.getStatus())){
                        continue;
                    }
                    ErpFinanceStatementDO newStatementDO = new ErpFinanceStatementDO();
                    newStatementDO.setId(statementDO.getId());
                    BigDecimal paymentAmount = paymentPriceMap.getOrDefault(statementDO.getId(), BigDecimal.ZERO);
                    BigDecimal currentAmount = statementDO.getTransactionAmount().add(paymentAmount);
                    newStatementDO.setTransactionAmount(currentAmount);
                    if(currentAmount.compareTo(statementDO.getTotalAmount()) == 0){
                        newStatementDO.setStatus(ALREADY_SETTLED.getStatus());
                    }else {
                        newStatementDO.setStatus(ErpFinanceStatementStatusEnum.PARTIAL_SETTLEMENT.getStatus());
                    }
                    statementList.add(newStatementDO);
                }
                break;
            case PROCESS:
                for (ErpFinanceStatementDO statementDO : financeStatementList) {
                    ErpFinanceStatementDO newStatementDO = new ErpFinanceStatementDO();
                    newStatementDO.setId(statementDO.getId());
                    BigDecimal paymentAmount = paymentPriceMap.getOrDefault(statementDO.getId(), BigDecimal.ZERO);
                    BigDecimal currentAmount = statementDO.getTransactionAmount().subtract(paymentAmount);
                    newStatementDO.setTransactionAmount(currentAmount);
                    if(BigDecimal.ZERO.compareTo(currentAmount) == 0){
                        newStatementDO.setStatus(ErpFinanceStatementStatusEnum.CONFIRMED.getStatus());
                    }else {
                        newStatementDO.setStatus(ErpFinanceStatementStatusEnum.PARTIAL_SETTLEMENT.getStatus());
                    }
                    statementList.add(newStatementDO);
                }
                break;
        }
        return statementList;
    }


}
